package com.zh.oauth.securety;

import com.alibaba.fastjson.JSON;
import com.zh.common.constans.AuthConstant;
import com.zh.common.entity.ElecMenu;
import com.zh.oauth.entity.ElecAuth;
import com.zh.oauth.entity.ElecRole;
import com.zh.oauth.entity.ElecUser;
import com.zh.oauth.service.ElecUserService;
import com.zh.oauth.util.AuthUtil;
import com.zh.oauth.util.MenuUtil;
import com.zh.oauth.util.RedisCache;
import com.zh.oauth.util.RoleUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;


import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service
public class UserDetailsServiceImpl implements UserDetailsService {


    @Autowired
    private ElecUserService elecUserService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Qualifier("taskExecutor")
    @Autowired
    private TaskExecutor executor;


    public UserDetailsServiceImpl() { }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        ElecUser user = elecUserService.selectUserDetail(username);
        // 将权限添加入用户实体并返回(供全局使用)
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        // 菜单列表
        List<ElecMenu> menus = new ArrayList<>();
        // 声明用户授权
        if (user == null) return null;
        // 状态为1 并且登录错误次数小于1
        if (user.getUserStatus() == 2)     // 状态为2 表示注销
            return new ElecUser(true, true, true, false, false);
        else if (user.getUserStatus() == 3)  // 状态为3，表示锁定
            return new ElecUser(false, true, true, true, false);
        else if (user.getUserErrorCount() > 5) // 错误登录次数为5,表示锁定
            return new ElecUser(false, true, true, true, false);
        else {
            // 从缓存中拿权限,没有则查询数据库
            List<String> auths = JSON.parseArray(JSON.toJSONString(this.redisTemplate.opsForValue().get(username + AuthConstant.REDIS_WEB_SERVE_KEY)), String.class);
            // 从缓存中拿菜单,没有则查询数据库
            menus = JSON.parseArray(JSON.toJSONString(this.redisTemplate.opsForValue().get(username + AuthConstant.REDIS_WEB_MENU_KEY)), ElecMenu.class);
            List<ElecAuth> authList = new ArrayList<>();
            Map<String, List<ElecAuth>> map = new HashMap<>();
            if (Objects.isNull(auths)) {
                authList = elecUserService.selectAuthByUserId(user.getId());
                List<String> list = new ArrayList<>();
                // 后端权限
                authList.forEach(auth -> {
                    if (auth.getAuthType() == 2)
                        grantedAuthorities.add(new SimpleGrantedAuthority(auth.getAuthPath()));
                    else
                        list.add(auth.getAuthPath());
                });
                redisTemplate.opsForValue().set(username + AuthConstant.REDIS_WEB_SERVE_KEY, list, 7, TimeUnit.DAYS);
            } else auths.forEach(auth -> grantedAuthorities.add(new SimpleGrantedAuthority(auth)));

            if (Objects.isNull(menus)) {
                // 获取所有菜单
                menus = elecUserService.selectMenuByUserId(user.getId());
                // 将整理过的菜单存入缓存
                redisTemplate.opsForValue().set(username + AuthConstant.REDIS_WEB_MENU_KEY, MenuUtil.getTreeData(menus), 7, TimeUnit.DAYS);
            }
            // 存储用户信息(24小时未重新登录则自定清理，否则不断刷新)
            redisTemplate.opsForValue().set(username + AuthConstant.USER_INFO, JSON.toJSONString(user), 24, TimeUnit.HOURS);

            // xxx 异步存储组装数据
            List<ElecAuth> finalAuthList = authList;

            executor.execute(new Runnable() {
                @Override
                public void run() {
                    // 获取角色列表
                    List<ElecRole> roles = elecUserService.selectRoleByUserId(user.getId());
                    // 整理过的角色存入缓存
                    redisTemplate.opsForValue().set(username + AuthConstant.USER_ROLE, RoleUtil.getTreeData(roles), 7, TimeUnit.DAYS);
                    // 用于构建权限树时使用
                    redisTemplate.opsForValue().set(username + AuthConstant.REDIS_AUTH_TREE, AuthUtil.getTreeData(finalAuthList), 7, TimeUnit.DAYS);
                }
            });
        }
        return new ElecUser(user.getId(), user.getUserRoleId(), user.getTypeId(),
                user.getForeignKeyId(), user.getForeignNo(), user.getForeignName(),
                user.getUserLoginName(), user.getUserPassword(),
                user.getAuthorities(),
                true, true, true, true, false);
    }


}
